﻿using System;
using System.Collections;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;

namespace FolderSize
{
    public class STreeNode : IEnumerable,ICollection
    {
        protected readonly char PATHCHAR = '\\';
        public STreeNode()
        {
            Childs = new List<STreeNode>();
            P_SyncRoot = new object();
        }
        protected int P_Key;
        protected object P_SyncRoot;
        protected int p_count;
        public Object SyncRoot { get { return P_SyncRoot; } }
        /// <summary>
        /// 文件名
        /// </summary>
        public int Key
        {
            get { return P_Key; }
            set
            {
                //if (string.IsNullOrWhiteSpace(value))
                //    throw new Exception("Name can not be null or empty");
                P_Key = value;
            }
        }
        public bool IsSynchronized { get { return false; } }
        public int Count
        {
            get
            {
                GetCount();
                return p_count;
            }
        }
        public override string ToString()
        {
            return this.Key.ToString();
        }
        public event Func<STreeNode, bool> EventBeforeAdd;
        public STreeNode Parent { get; set; }
        public List<STreeNode> Childs { get; protected set; }

        public void AddChild(params STreeNode[] nodes)
        {
            for (int i = 0; i < nodes.Length; i++)
            {
                //foreach (STreeNode tempNode in this)
                //{
                //    if (tempNode.Key.Equals(nodes[i].Key))
                //    {
                //        throw new Exception("Key can not be duplicated");
                //    }
                //}
                if (EventBeforeAdd != null)
                {
                    if (EventBeforeAdd(nodes[i]))
                    {
                        DoAddNode(nodes, i);
                    }
                }
                else
                {
                    DoAddNode(nodes, i);
                }
            }
        }

        private void DoAddNode(STreeNode[] nodes, int i)
        {
            nodes[i].Parent = this;
            Childs.Add(nodes[i]);
        }
        public void RemoveChild(params STreeNode[] nodes)
        {
            for (int i = 0; i < nodes.Length; i++)
            {
                nodes[i].Parent = null;
                Childs.Remove(nodes[i]);
            }
        }
        /// <summary>
        /// 获取同级别的兄弟节点
        /// </summary>
        /// <returns></returns>
        public List<STreeNode> GetBrothers()
        {
            if (this.Parent != null)
            {
                List<STreeNode> childsOfPapaList = new List<STreeNode>(this.Parent.Childs);
                childsOfPapaList.Remove(this);
                return childsOfPapaList;
            }
            return null;
        }

        public IEnumerator GetEnumerator()
        {
            return new TreeEnum(this);
        }

        /// <summary>
        /// 获取从根目录到当前的全部路径
        /// </summary>
        /// <returns></returns>
        public string GetPath()
        {
            StringBuilder path = new StringBuilder();
            STreeNode tempNode = this;
            do
            {
                path.Insert(0, tempNode.Key);
                path.Insert(0, PATHCHAR);
                tempNode = tempNode.Parent;
            }
            while (tempNode != null);
            path.Insert(0, PATHCHAR);
            return path.ToString();
        }
        /// <summary>
        /// 遍历整棵树，查找第一个名字匹配的节点
        /// </summary>
        /// <param name="key"></param>
        /// <returns></returns>
        public STreeNode GetFirstChildNodeByName(int key)
        {
            foreach (STreeNode n in this)
            {
                if (n.Key == key)
                {
                    if (n == this)
                        continue;
                    else
                        return n;
                }
            }
            return null;
        }
        /// <summary>
        /// 遍历整棵树，查找所有名字匹配的节点
        /// </summary>
        /// <param name="name"></param>
        /// <returns></returns>
        public List<STreeNode> GetAllChildNodeByName(int key)
        {
            List<STreeNode> ret = new List<STreeNode>();
            foreach (STreeNode n in this)
            {
                if (n.Key == key)
                {
                    if (n == this)
                        continue;
                    else
                        ret.Add(n);
                }
            }
            return ret;
        }
        /// <summary>
        /// 根据路径，查找相应的节点
        /// </summary>
        /// <param name="path"></param>
        /// <returns></returns>
        public STreeNode GetNodeByPath(string path)
        {
            STreeNode tempNode = new STreeNode();
            STreeNode orgParent = this.Parent;
            tempNode.AddChild(this);
            this.Parent = orgParent;
            string[] paths = path.Trim().Split(PATHCHAR);

            for (int i = 0; i < paths.Length; i++)
            {
                if (!string.IsNullOrEmpty(paths[i]))
                {
                    int tempPath = int.Parse(paths[i]);
                    tempNode = tempNode.Childs.Find(a => a.Key == tempPath);
                    if (tempNode == null)
                        return null;
                }
            }
            return tempNode;
        }
        /// <summary>
        /// 将这个可爱的树，复制到指定的数组中。
        /// </summary>
        /// <param name="array"></param>
        /// <param name="index"></param>
        public void CopyTo(Array array, int index=0)
        {
            TreeEnum te = new TreeEnum(this);
            int teCount = te.Count;
            for (int i = index, j = 0; j < teCount && i < array.Length; i++, j++)
            {
                array.SetValue(te.collection.Dequeue(), i);
            }
        }
        protected void GetCount()
        {
            p_count = 0;
            CountTree(this);
        }
        private void CountTree(STreeNode _collection)
        {
            //前序遍历
            p_count++;
            if (_collection.Childs != null && _collection.Childs.Count > 0)
                foreach (STreeNode child in _collection.Childs)
                {
                    CountTree(child);
                }
        }
        /// <summary>
        /// 获取HierarchyID，这是sql server 2008 提供的新类型，用于表征树状结构
        /// </summary>
        /// <returns></returns>
        public string GetHierarchyIDStr()
        {
            StringBuilder path = new StringBuilder();
            STreeNode tempNode = this;
            path.Append("/");
            while (tempNode.Parent!=null)
            {
                path.Insert(0, tempNode.Parent.Childs.IndexOf(tempNode)+1);
                path.Insert(0, '/');
                tempNode = tempNode.Parent;
            }
            return path.ToString();
        }
    }

    class TreeEnum : IEnumerator
    {
        private STreeNode rootNode;
        private STreeNode curNode;
        public Queue<STreeNode> collection;
        public int Count { get { return collection.Count; } }
        public TreeEnum(STreeNode _collection)
        {
            rootNode = _collection;

            collection = new Queue<STreeNode>();
            FillQueue(rootNode);
            curNode = rootNode;
        }

        private void FillQueue(STreeNode _collection)
        {
            //前序遍历
            collection.Enqueue(_collection);
            if (_collection.Childs != null && _collection.Childs.Count > 0)
                foreach (STreeNode child in _collection.Childs)
                {
                    FillQueue(child);
                }
        }

        public bool MoveNext()
        {
            if (collection.Count > 0)
            {
                curNode = collection.Dequeue();
                return true;
            }
            else
                return false;
        }


        public void Reset()
        {
            collection = new Queue<STreeNode>();
            FillQueue(rootNode);
            curNode = rootNode;
        }

        public STreeNode Current
        {
            get { return curNode; }
        }


        object IEnumerator.Current
        {
            get { return Current; }
        }

    }
}
